﻿using System;
using System.Collections.Generic;
using System.Linq;
using LoA.Shared.Input;
using LoA.Shared.Interfaces;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace LoA.InputEngine {
	/// <summary>
	/// This is a game component that implements IUpdateable.
	/// </summary>
	public partial class InputComponent : DrawableGameComponent, IInput {
		private static InputComponent _current = null;
		public static InputComponent Current { get { return _current; } }

		public InputComponent(Game game)
			: base(game) {
			if (_current == null) {
				_current = this;
			}

			MoveTimeOut = TimeSpan.FromSeconds(1.0);

			// Construct the master list of moves.
			moves = new MoveSequence[ ]
                {
                    new MoveSequence("Jump",        Buttons.A) { IsSubMove = true },
                    new MoveSequence("Punch",       Buttons.X) { IsSubMove = true },
                    new MoveSequence("Double Jump", Buttons.A, Buttons.A),
                    new MoveSequence("Jump Kick",   Buttons.A | Buttons.X),
					//new Move("Quad Punch",  Buttons.X, Buttons.Y, Buttons.X, Buttons.Y),                    
					//new Move("Fireball",    Direction.Down, Direction.DownRight,
					//						Direction.Right | Buttons.X),
                    new MoveSequence("Long Jump",   InputDirection.Up, InputDirection.Up, Buttons.A),
                    new MoveSequence("Back Flip",   InputDirection.Down, InputDirection.Down | Buttons.A),
					//new Move("30 Lives",    Direction.Up, Direction.Up,
					//						Direction.Down, Direction.Down,
					//						Direction.Left, Direction.Right,
					//						Direction.Left, Direction.Right,
					//						Buttons.B, Buttons.A),
                };

			// Construct a move list which will store its own copy of the moves array.
			moveList = new MoveSequenceCollection(moves);

			// Create an InputManager for each player with a sufficiently large buffer.
			inputManagers = new InputManager[4];
			for (int i = 0; i < inputManagers.Length; ++i) {
				inputManagers[i] =
					new InputManager((PlayerIndex)i, moveList.LongestMoveLength);
			}

			// Give each player a location to store their most recent move.
			playerMoves = new MoveSequence[inputManagers.Length];
			playerMoveTimes = new TimeSpan[inputManagers.Length];
		}

		/// <summary>
		/// This is the master list of moves in logical order. This array is kept
		/// around in order to draw the move list on the screen in this order.
		/// </summary>
		private MoveSequence[ ] moves;
		/// <summary>
		/// The move list used for move detection at runtime.
		/// </summary>
		private MoveSequenceCollection moveList;

		/// <summary>
		/// The move list is used to match against an input manager for each player.
		/// </summary>
		private InputManager[ ] inputManagers;

		/// <summary>
		/// Stores each players' most recent move and when they pressed it.
		/// </summary>
		private MoveSequence[ ] playerMoves;
		private TimeSpan[ ] playerMoveTimes;

		/// <summary>
		/// Time until the currently "active" move dissapears from the screen.
		/// </summary>
		private readonly TimeSpan MoveTimeOut;

		/// <summary>
		/// Allows the game component to perform any initialization it needs to before starting
		/// to run.  This is where it can query for any required services and load content.
		/// </summary>
		public override void Initialize( ) {
			this.Suspended = false;

			base.Initialize( );
		}

		public InputManager GetInputManager(PlayerIndex playerIndex) {
			return this.inputManagers[(int)playerIndex];
		}

		public bool Suspended { get; private set; }
		public void Suspend( ) { this.Suspended = true; }
		public void Resume( ) { this.Suspended = false; }

		IInputManager IInput.GetInputManager(PlayerIndex playerIndex) {
			return this.GetInputManager(playerIndex);
		}
	}
}
